
#include <QDateTime>
#include <stdlib.h>


#include "RateCount.h"


#include <time.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#ifdef WIN32
int gettimeofday(struct timeval *tp, void *tzp)
{
  time_t clock;
  struct tm tm;
  SYSTEMTIME wtm;
  GetLocalTime(&wtm);
  tm.tm_year   = wtm.wYear - 1900;
  tm.tm_mon   = wtm.wMonth - 1;
  tm.tm_mday   = wtm.wDay;
  tm.tm_hour   = wtm.wHour;
  tm.tm_min   = wtm.wMinute;
  tm.tm_sec   = wtm.wSecond;
  tm. tm_isdst  = -1;
  clock = mktime(&tm);
  tp->tv_sec = clock;
  tp->tv_usec = wtm.wMilliseconds * 1000;
  return (0);
}
#endif
static uint64_t GetUSec()
{
       struct timeval time;

       gettimeofday(&time,NULL);

       return (time.tv_sec * 1000000 + time.tv_usec);

}
struct RateCount
{
    uint64_t usecStart;
    uint64_t usecSamplePeriod;
    int64_t nTotalCount;
    int32_t nSampleCapacity;

    int64_t * nSamples;
    uint64_t * usecSamplesStartTimes;

    int32_t nNowSample;
    int32_t nOldestSample;
};

static int32_t SampleSelfPlus(int32_t nNowSample, int32_t nCapacity)
{
    int32_t nTmpSample = nNowSample + 1;
    if(nTmpSample == nCapacity){
        nTmpSample = 0;
    }
    return nTmpSample;
}



struct RateCount* RateCountInit(uint64_t msSamplePeriod, int32_t nSampleCapacity)
{
    struct RateCount * pRate = (struct RateCount*)calloc(1, sizeof(struct RateCount));
    pRate->nNowSample=0;
    pRate->nOldestSample=0;
    pRate->nTotalCount=0;
    pRate->usecStart = GetUSec();
    pRate->usecSamplePeriod = msSamplePeriod*1000;
    pRate->nSampleCapacity = nSampleCapacity;
    pRate->nSamples = (int64_t*)calloc(1, sizeof(int64_t)*nSampleCapacity);
    if(pRate->nSamples==NULL)
    {
          free(pRate);
          pRate=NULL;
          return NULL;
    }
    pRate->usecSamplesStartTimes = (uint64_t*)calloc(1, sizeof(uint64_t)*nSampleCapacity);
    if(pRate->usecSamplesStartTimes==NULL)
    {
          free(pRate->nSamples);
          pRate->nSamples=NULL;
          free(pRate);
          pRate=NULL;
          return NULL;
    }
    pRate->usecSamplesStartTimes[pRate->nNowSample] = pRate->usecStart;
    return pRate;
}
void RateCountReset(struct RateCount * pRate)
{

    pRate->nNowSample=0;
    pRate->nOldestSample=0;
    pRate->nTotalCount=0;
    pRate->usecStart = GetUSec();
    pRate->usecSamplesStartTimes[pRate->nNowSample] = pRate->usecStart;


}
void RateCountDestroy(struct RateCount * pRate)
{
    if(pRate!=NULL)
    {
        if(pRate->nSamples!=NULL)
        {
            free(pRate->nSamples);
            pRate->nSamples=NULL;
        }
        if(pRate->usecSamplesStartTimes!=NULL)
        {
            free(pRate->usecSamplesStartTimes);
            pRate->usecSamplesStartTimes=NULL;
        }
        free(pRate);
        pRate=NULL;
    }



}

void SampleInsert(struct RateCount * pRate, int64_t nSample)
{
    uint64_t usecNow = GetUSec();
    if(pRate->usecSamplesStartTimes[pRate->nNowSample] + pRate->usecSamplePeriod > usecNow){
        pRate->nSamples[pRate->nNowSample] += nSample;
    }
    else{
        uint64_t usecGap = usecNow - pRate->usecSamplesStartTimes[pRate->nNowSample];
        usecGap%=(pRate->usecSamplePeriod*pRate->nSampleCapacity);
        while(usecGap > pRate->usecSamplePeriod){
            int32_t nNext = SampleSelfPlus(pRate->nNowSample, pRate->nSampleCapacity);
            pRate->usecSamplesStartTimes[nNext] = pRate->usecSamplesStartTimes[pRate->nNowSample] + pRate->usecSamplePeriod;
            pRate->nSamples[nNext] = 0;
            pRate->nNowSample = nNext;
            usecGap -= pRate->usecSamplePeriod;
            if(pRate->nOldestSample == pRate->nNowSample){
                pRate->nOldestSample = SampleSelfPlus(pRate->nOldestSample, pRate->nSampleCapacity);
            }
        }
        pRate->usecSamplesStartTimes[pRate->nNowSample] = usecNow;
        pRate->nSamples[pRate->nNowSample] = nSample;
    }
    pRate->nTotalCount += nSample;
}

double GetTmpRate(struct RateCount * pRate)
{
    if(pRate==NULL)
          return 0.0;
    int32_t i;
    int64_t nCount = 0;
    uint64_t usecTimeGap;
    double dResult = 0.0;
    SampleInsert(pRate, 0);
    usecTimeGap = GetUSec() - pRate->usecSamplesStartTimes[pRate->nOldestSample];
    for( i = 0; i < pRate->nSampleCapacity; i ++ ){
        if(pRate->usecSamplesStartTimes[i] != 0){
            nCount += pRate->nSamples[i];
        }
    }
    dResult = (double)(nCount*1000000) / usecTimeGap;
    return dResult;
}

int64_t GetTotalCount(struct RateCount * pRate)
{
    return pRate->nTotalCount;
}

uint64_t GetTotalTime(struct RateCount * pRate)
{
    uint64_t usecRet = GetUSec() - pRate->usecStart;
    return usecRet;
}


